/**
 * ****************************************************************************
 * Implementation of the eventBus
 *
 * @author Ouyang Qi
 * @version 1.0.0 2008/11/14 (Standardized-OK)
 * <PRE>
 * [Revision History]
 * 2008/09/26    ver1.0.0    Creation        Ouyang Qi
 * </PRE>
 * Copyright 2008 USI, All rights reserved.
 * ***************************************************************************
 */

/**
 * @namespace EventBus is subscribe type event framework.
 */
var EventBus = {
		
	/**
	 * subscribers list. 
	 <pre>
	 [{selector : "path.to.event",
	   id : componentId,
	   callback : function(){} }, ... ]
	 </pre>
	 * @fieldOf EventBus
	 */
	_subscribes : [],
	
	/**
	 * 
	 * Allows registration of interest in named events based on an event
	 * name. Event names are expressed as tokens separated by the "."
	 * character.
	 * @methodOf EventBus
	 * @param selector
	 *            String The selector of the event to listen for
	 * @param callback
	 *            Function A function object reference or the name of a
	 *            function to be called when the document is loaded.
	 * @param componentId
	 *            String
	 * 
	 */
	subscribe : function(selector, callback, componentId) {
		var data = {
			callback : callback,
			id : componentId,
			selector : selector
		};
		this._subscribes.push(data);
	},

	/**
	 * Un-subscribe from list.
	 * if selector is null, it un-subscribe all in component.
	 * @methodOf EventBus
	 * @param selector
	 *            String The selector of the event to listen for
	 * @param componentId
	 *            String
	 */
	unsubscribe : function(selector, componentId) {
		var removed = [];
		for(var i = 0, l = this._subscribes.length; i < l; i++){
			var rdata = this._subscribes[i];
			if(rdata.id != componentId || (selector && rdata.selector != selector )){
				removed.push(rdata);
			}
		}
		this._subscribes = removed;
	},

	/**
	 * publish event
	 * @methodOf EventBus
	 * @param path
	 *            String The selector of the event that is being broadcast.
	 * @param message
	 *            Object Optional, can be null. An arbitrary Object holding
	 *            extra information that will be passed as an argument to
	 *            the handler function.
	 * @param componentId
	 *            String
	 */
	publish : function(path, message, componentId) {
		var list = this._collect(path, componentId);
		list.each(function(data){
			var cb = data.callback;
			cb(path, message, data.id);
		});
	},

	/**
	 * collect by selector and component-id
	 * @methodOf EventBus
	 * @param selector
	 *            String example) path.to.me or path.to.*
	 * @param componentId
	 *            String componentId when it subscribe
	 * @return Array subscribed data list.
	 */
	_collect : function(path, componentId) {
		var list = [];
		for ( var i = 0, l = this._subscribes.length; i < l; i++) {
			var data = this._subscribes[i];
			if (this._selectorMatch(data.selector, path)) {
				if (!componentId || data.id == componentId) {
					list.push(data);
				}
			}
		}
		return list;
	},

	/**
	 * match selector and event path selector support 1. path.to.event 2.
	 * path.to.* [ path.to.a , path.to.b] 3. path.to.** [ path.to,
	 * path.to.a, path.to.a.b]
	 * @methodOf EventBus
	 * @param selector
	 *            String example) path.to.me or path.to.*
	 * @param path
	 *            String
	 * @return Boolean is match selector and path.
	 */
	_selectorMatch : function(selector, path) {
		if (selector.lastIndexOf('.**') > -1) {
			var selarry = selector.split('.');
			selarry.pop();

			var slength = selarry.length;
			selector = selarry.join('.');

			var patharry = path.split('.');
			path = patharry.slice(0, slength).join('.');

		} else if (selector.lastIndexOf('.*') > -1) {
			var selv = selector.split('.');
			selv.pop();
			selector = selv.join('.');
			var pathv = path.split('.');
			pathv.pop();
			path = pathv.join('.');
		}
		return path == selector;
	},
	/**
	 * unsubscribe all.
	 * @methodOf EventBus
	 */
	_clear : function() {
		this._subscribes = [];
	}
};

